package com.atom.module.lib.opengles.egl

import android.graphics.Bitmap
import android.opengl.EGL14
import android.opengl.GLES20
import com.atom.module.lib.opengles.util.ShaderUtils
import java.io.*
import java.nio.ByteBuffer
import java.nio.ByteOrder
import kotlin.jvm.Throws

open class EGLSurfaceWrapper(private val eglWrapper: EGLWrapper) {

    protected var width = -1
        get() {
            if (field < 0) {
                EGLHelper.querySurfaceWidth(eglWrapper)
            }
            return field
        }
    protected var height = -1
        get() {
            if (field < 0) {
                EGLHelper.querySurfaceHeight(eglWrapper)
            }
            return field
        }

    fun release() {
        EGLHelper.destroySurface(eglWrapper)
        eglWrapper.setSurface(EGL14.EGL_NO_SURFACE, EGLWrapper.SurfaceType.NONE)
        height = -1
        width = -1
    }

    @Suppress("MemberVisibilityCanBePrivate")
    fun toOutputStream(
        stream: OutputStream,
        format: Bitmap.CompressFormat = Bitmap.CompressFormat.PNG
    ) {
        if (!eglWrapper.isCurrent()) throw RuntimeException("Expected EGL context/surface is not current")
        val width = this.width
        val height = this.height
        val buf = ByteBuffer.allocateDirect(width * height * 4)
        buf.order(ByteOrder.nativeOrder())
        GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf)
        ShaderUtils.checkGLError("glReadPixels")
        buf.rewind()
        val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        bitmap.copyPixelsFromBuffer(buf)
        bitmap.compress(format, 90, stream)
        bitmap.recycle()
    }

    /**
     * Saves the EGL surface to a file.
     * Expects that this object's EGL surface is current.
     */
    @Suppress("unused")
    @Throws(IOException::class)
    fun toFile(file: File, format: Bitmap.CompressFormat = Bitmap.CompressFormat.PNG) {
        var stream: BufferedOutputStream? = null
        try {
            stream = BufferedOutputStream(FileOutputStream(file.toString()))
            toOutputStream(stream, format)
        } finally {
            stream?.close()
        }
    }

    /**
     * Saves the EGL surface to given format.
     * Expects that this object's EGL surface is current.
     */
    fun toByteArray(format: Bitmap.CompressFormat = Bitmap.CompressFormat.PNG): ByteArray {
        val stream = ByteArrayOutputStream()
        stream.use {
            toOutputStream(it, format)
            return it.toByteArray()
        }
    }
}